#ifndef GRUB_EFI_TPCM_HEADER
#define GRUB_EFI_TPCM_HEADER 1

#define GRUB_EFI_HASH2_SERVICE_BINDING_PROTOCOL_GUID \
  { \
    0xda836f8d, 0x217f, 0x4ca0, { 0x99, 0xc2, 0x1c, 0xa4, 0xe1, 0x60, 0x77, 0xea } \
  }

#define GRUB_EFI_HASH2_PROTOCOL_GUID \
  { \
    0x55b1d734, 0xc5e1, 0x49db, { 0x96, 0x47, 0xb1, 0x6a, 0xfb, 0xe, 0x30, 0x5b } \
  }

#define EFI_TPCM_GUID \
  { \
    0xa37e200e, 0xda90, 0x473b, { 0x8b, 0xb5, 0x1d, 0x7b, 0x11, 0xba, 0x32, 0x33 } \
  }

#define GRUB_HASH_ALGORITHM_SM3_GUID \
  { \
    0x9DCD754B, 0x3479, 0x27AD, { 0x56, 0x4C, 0x68, 0x7C, 0x68, 0xEC, 0xF9, 0xB9 } \
  }


#define OEM_SIG_SIZE                3
#define FIRMWARE_VERSION_SIZE       32
#define FIRMWARE_HASH_CONTENT_SIZE  32
#define FIRMWARE_NAME_SIZE          32
#define GRUB_IPMI_TIMEOUT_MS        2000

// LUN
#define IPMI_BMC_LUN                0x00
// Net Function Definition
#define IPMI_NETFN_OEM              0x30

#define IPMI_CMD_GET_MEASURE_PARM   0x92 //change a name

#define IPMI_SUB_CMD_MEASURE_REQ    0x57 //change a name
#define IPMI_SUB_CMD_CONTROL_REQ    0x58
#define IPMI_SUB_CMD_SWITCH_REQ     0x59

//bmeasure
#define DEFAULT_HASH_SIZE                   32
#define MEASURE_DATA_MEM_SIZE               0x100000

#define TPCM_TAG_REQ_COMMAND                0x000000C1 
#define TPCM_ORD_ExternSimpleBootMeasure    0x00001053

typedef struct {
    grub_efi_uint32_t uiCmdTag;
    grub_efi_uint32_t uiCmdLength;
    grub_efi_uint32_t uiCmdCode;
    grub_efi_uint32_t uiPcr;
    grub_efi_uint32_t uiStage;
    grub_efi_uint8_t  uaDigest[DEFAULT_HASH_SIZE];
    grub_efi_uint32_t uiObjLen;
    grub_efi_uint8_t  uaObj[FIRMWARE_NAME_SIZE];
}extern_simple_bmeasure_req_st;

typedef struct {
    grub_efi_uint8_t  OemSignature[OEM_SIG_SIZE];
    grub_efi_uint8_t  SubCmd;
    grub_efi_uint8_t  FirmwareType;
    grub_efi_uint8_t  FirmwareDetailType;
    grub_efi_uint8_t  FirmwareHashAlgoType;
    grub_efi_uint8_t  FirmwareHashLen;
    extern_simple_bmeasure_req_st FirmwareHashContent;
    // reserved for kernel and initrd's version
    grub_efi_uint8_t  FirmwareVerionLen;
    grub_efi_uint8_t  FirmwareVerion[0];
} OEM_BMC_MEASURE_REQUSET;

typedef struct {
    grub_efi_uint8_t  CompletionCode;
    grub_efi_uint8_t  OemSignature[OEM_SIG_SIZE];
} OEM_BMC_MEASURE_RESPONSE;

typedef struct {
    grub_efi_uint8_t  OemSignature[OEM_SIG_SIZE];
    grub_efi_uint8_t  SubCmd;
    grub_efi_uint8_t  FirmwareType;
    grub_efi_uint8_t  FirmwareDetailType;
} OEM_BMC_GET_RESULT_REQUSET;

typedef struct {
    /* In the specification of BMC <--> BIOS(GRUB2), we need CompletionCode
     * But, BIOS has pre-processed CompletionCode in function: excute_ipmi_cmd
     * So, we delete the word:
     * grub_efi_uint8_t  CompletionCode;
     */
    grub_efi_uint8_t  OemSignature[OEM_SIG_SIZE];
    grub_efi_uint8_t  ControlResult;
} OEM_BMC_GET_RESULT_RESPONSE;

typedef struct {
    grub_efi_uint8_t  OemSignature[OEM_SIG_SIZE];
    grub_efi_uint8_t  SubCmd;
    grub_efi_uint8_t  FirmwareType;
    grub_efi_uint8_t  FirmwareDetailType;
} OEM_BMC_GET_SWITCH_REQUSET;

typedef struct {
    /* In the specification of BMC <--> BIOS(GRUB2), we need CompletionCode
     * But, BIOS has pre-processed CompletionCode in function: excute_ipmi_cmd
     * So, we delete the word:
     * grub_efi_uint8_t  CompletionCode;
     */
    grub_efi_uint8_t  OemSignature[OEM_SIG_SIZE];
    grub_efi_uint8_t  ControlResult;
} OEM_BMC_GET_SWITCH_RESPONSE;

typedef enum {
    IPMI_SYSTEM_INTERFACE_UNKNOWN,  // IPMI_SYSTEM_INTERFACE_TYPE->UNKNOWN
    IPMI_SYSTEM_INTERFACE_KCS,
    IPMI_SYSTEM_INTERFACE_SMIC,
    IPMI_SYSTEM_INTERFACE_BT, // IPMI_SYSTEM_INTERFACE_TYPE->BT
    IPMI_SYSTEM_INTERFACE_SSIF,
    IPMI_SYSTEM_INTERFACE_MAX_TYPE // IPMI_SYSTEM_INTERFACE_TYPE->MAX_TYPE
} grub_ipmi_system_interface_type;


typedef struct {
    grub_efi_uint8_t lun : 2;
    grub_efi_uint8_t net_fn : 6;
    grub_efi_uint8_t cmd;
} grub_ipmi_cmd_header;

typedef enum {
    IPMI_MEMORY,
    IPMI_IO, // IPMI_IO
    IPMI_MAX_INTERFACE_ADDRESS_TYPE
} grub_ipmi_interface_address_type;

typedef enum {
    IPMI_FW_SHIM,
    IPMI_FW_SHIM_GRUB,
    IPMI_FW_OS
} grub_ipmi_firmware_type;

typedef enum {
    IPMI_FW_DETAIL_GRUB_CFG,
    IPMI_FW_DETAIL_KERNEL,
    IPMI_FW_DETAIL_INITRD
} grub_ipmi_firmware_detail_type;

typedef enum {
    IPMI_FW_HASH_SM3,
    IPMI_FW_HASH_RESERVED1,
    IPMI_FW_HASH_RESERVED2
} grub_ipmi_firmware_hash_algo_type;

typedef enum {
    IPMI_MEASURE_UNKNOW,
    IPMI_MEASURE_SUCCESS,
    IPMI_MEASURE_FAIL
} grub_ipmi_measure_result_type;

typedef enum {
    IPMI_TPCM_UNKNOW,
    IPMI_TPCM_OPEN,
    IPMI_TPCM_CLOSE,
    IPMI_TPCM_PERMISSIVE
} grub_ipmi_tpcm_result_type;


typedef grub_efi_uint8_t EFI_MD5_HASH2[16];
typedef grub_efi_uint8_t EFI_SHA1_HASH2[20];
typedef grub_efi_uint8_t EFI_SHA224_HASH2[28];
typedef grub_efi_uint8_t EFI_SHA256_HASH2[32];
typedef grub_efi_uint8_t EFI_SHA384_HASH2[48];
typedef grub_efi_uint8_t EFI_SHA512_HASH2[64];
typedef grub_efi_uint8_t EFI_SM3_HASH2[32];

typedef union {
  EFI_MD5_HASH2       Md5Hash;
  EFI_SHA1_HASH2      Sha1Hash;
  EFI_SHA224_HASH2    Sha224Hash;
  EFI_SHA256_HASH2    Sha256Hash;
  EFI_SHA384_HASH2    Sha384Hash;
  EFI_SHA512_HASH2    Sha512Hash;
  EFI_SM3_HASH2       Sm3Hash;
} grub_efi_hash2_output;

struct grub_efi_hash2_protocol {
  grub_efi_status_t
  (*get_hash_size) (struct grub_efi_hash2_protocol *this,
                    grub_guid_t *hash_algorithm,
                    grub_efi_uintn_t hash_size);

  grub_efi_status_t
  (*hash) (struct grub_efi_hash2_protocol *this,
           grub_guid_t *hash_algorithm,
           grub_efi_uint8_t *message,
           grub_efi_uintn_t message_size,
           grub_efi_hash2_output *hash);

  grub_efi_status_t
  (*hash_init) (struct grub_efi_hash2_protocol *this,
                grub_guid_t *hash_algorithm);

  grub_efi_status_t
  (*hash_update) (struct grub_efi_hash2_protocol *this,
                  grub_efi_uint8_t *message,
                  grub_efi_uintn_t message_size);

  grub_efi_status_t
  (*hash_final) (struct grub_efi_hash2_protocol *this,
                 grub_efi_hash2_output *hash);
};
typedef struct grub_efi_hash2_protocol grub_efi_hash2_protocol_t;

struct grub_efi_ipmi_interface_protocol {
  grub_efi_status_t
  (*excute_ipmi_cmd) (struct grub_efi_ipmi_interface_protocol *this,
                      grub_ipmi_cmd_header request,
                      void *send_data,
                      grub_efi_uint8_t send_length,
                      void *recv_data,
                      grub_efi_uint8_t *recv_length,
                      grub_efi_uint16_t *status_codes);

  grub_ipmi_system_interface_type
  (*get_ipmi_interface_type) (struct grub_efi_ipmi_interface_protocol *this);

  grub_efi_uint16_t
  (*get_ipmi_base_address) (struct grub_efi_ipmi_interface_protocol *this);

  grub_ipmi_interface_address_type
  (*get_ipmi_base_address_type) (struct grub_efi_ipmi_interface_protocol *this);

  grub_efi_uint8_t
  (*get_ipmi_version) (struct grub_efi_ipmi_interface_protocol *this);
};
typedef struct grub_efi_ipmi_interface_protocol grub_efi_ipmi_interface_protocol_t;

#endif
